﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LED_Editor.Model;
using NUnit.Framework;
using System.Collections;
using LED_Editor.ControllerProgramming;

namespace LED_UnitTest
{
    public delegate void ByteArrayReceivingEventHandler(object sender, ByteArrayReceivingEventArgs e);

    public class ByteArrayReceivingEventArgs :EventArgs 
    {
        public ByteArrayReceivingEventArgs()
        {
            Bytes = new byte []{};
        }
        public byte[] Bytes {get;set;}
    }
    public struct SimpleQuery
    {
        public char Command { get; set; }
        public byte Address { get; set; }

        public byte[] ToByteArray()
        {
            List<byte> bytes = new List<byte>();
            bytes.Add(Address) ;
            bytes.Add(Convert.ToByte(Command));
            return bytes.ToArray(); 
        }
    }

    public class TestControllerProgrammingStrategy : BasicControllerProgrammingStrategy
    {
        public event ByteArrayReceivingEventHandler ByteArrayReceiving;

        private void OnByteArrayReceiving(ref byte[] bytes)
        {
            ByteArrayReceivingEventArgs args = new ByteArrayReceivingEventArgs() { Bytes = bytes };
            if (ByteArrayReceiving != null)
            {
                ByteArrayReceiving(this, args);
            }
            bytes = args.Bytes;
        }
        
        public override object WaitAnswer()
        {
            Log("Ожидание ответа...");

            byte[] answer = new byte[] { };

            int address = 0;
            int result = 0;

            while (true)
            {
                OnByteArrayReceiving(ref answer);

                if (answer.Length == 2)
                {
                    address = answer[0];
                    result = answer[1];

                    if (address == Address)
                        break;
                }
                else
                {
                    throw new ControllerException("Answer from controller has lenght <> 2");
                }

            }
            return (byte)result;
        }
    }

    public class TestController : Controller
    {
        private TestControllerProgrammingStrategy _controllerProgrammingStrategy;
        protected override IControllerProgrammingStrategy ControllerProgrammingStrategy
        {
            get
            {
                if (_controllerProgrammingStrategy == null)
                    _controllerProgrammingStrategy = new TestControllerProgrammingStrategy();
                return _controllerProgrammingStrategy;
            }
        }

       
        public IControllerProgrammingStrategy Strategy
        {
            get
            {
                return ControllerProgrammingStrategy;
            }
        }

       

    }
    [TestFixture]
    public class ProgrammingControllerAlgorithmTest
    {

        private TestController _controller;
        Queue<SimpleQuery> controllerAnswers;
        [SetUp]
        public void Setup()
        {
            _controller = new TestController();
            _controller.Address = 1;
            _controller.Logging += new LoggingEventHandler(_controller_Logging);
           ((TestControllerProgrammingStrategy) _controller.Strategy).ByteArrayReceiving += new ByteArrayReceivingEventHandler(_controller_ByteArrayReceiving);  
        }

        void _controller_ByteArrayReceiving(object sender, ByteArrayReceivingEventArgs e)
        {
            //List<byte> bytes = new List<byte>();
            //bytes.Add(_controller.Address);
            //bytes.Add(Convert.ToByte(controllerAnswers.Dequeue()));
            SimpleQuery query = controllerAnswers.Dequeue();
            e.Bytes = query.ToByteArray();
        }

        void _controller_Logging(object sender, LogEventArgs e)
        {
            Console.WriteLine(e.Message);
        }
        [Test]
        public void ValidAlgorithmFlow()
        {
            //готов ли контроллер?
            EnqueueControllerAnswer('1');
            //flash заполнен
            EnqueueControllerAnswer('1');
            //flash стерт
            EnqueueControllerAnswer('R');
            //flash пуст
            EnqueueControllerAnswer('0');
            //пуст и готов к прошивке
            EnqueueControllerAnswer('e');
            //ожидание фрэйма 1
            EnqueueControllerAnswer('R');
            //фрэйм 1 принят
            EnqueueControllerAnswer('R');
            //ожидание фрэйма 2
            EnqueueControllerAnswer('R');
            //фрэйм 2 принят
            EnqueueControllerAnswer('R');
            //завершение прошивки
            EnqueueControllerAnswer('R');

 
            for (int i = 0; i < 2; i++)
			{
                _controller.Frames.Add(GetRandomFrame());
			}

            _controller.Programme();
        }

        [Test]
        public void ValidAlgorithmFlow_NoFrames()
        {
            //готов ли контроллер?
            EnqueueControllerAnswer('1');
            //flash заполнен
            EnqueueControllerAnswer('1');
            //flash стерт
            EnqueueControllerAnswer('R');
            //flash пуст
            EnqueueControllerAnswer('0');
            //пуст и готов к прошивке
            EnqueueControllerAnswer('e');
            //завершение прошивки
            EnqueueControllerAnswer('R');

            _controller.Programme();
        }

        private void EnqueueControllerAnswer(char query, byte address)
        {
            if (controllerAnswers == null)
            {
                controllerAnswers = new Queue<SimpleQuery>();
            }
            controllerAnswers.Enqueue(new SimpleQuery(){Command=query,Address=address} ) ;
        }

        private void EnqueueControllerAnswer(char query)
        {
            EnqueueControllerAnswer(query, _controller.Address);
        }

       
        [Test]
        public void ValidAlgorithmFlow_FlashIsEmpty()
        {
            //готов ли контроллер?
            EnqueueControllerAnswer('1');
            //flash пуст
            EnqueueControllerAnswer('0');
            //пуст и готов к прошивке
            EnqueueControllerAnswer('e');
            //завершение прошивки
            EnqueueControllerAnswer('R');

            _controller.Programme();
        }

        [Test,ExpectedException(typeof (ControllerException )) ]
        public void ValidAlgorithmFlow_ControllerIsNotReady()
        {
            //готов ли контроллер? - ответим КУ
            EnqueueControllerAnswer('Q');

            _controller.Programme();
        }
        
        private FrameStruct GetRandomFrame()
        {
            FrameStruct frame1 = new FrameStruct();
            frame1.Duration = 1;

            frame1.StartR = 20;
            frame1.StartG = 120;
            frame1.StartB = 220;

            frame1.EndR = 20;
            frame1.EndG = 120;
            frame1.EndB = 220;

            return frame1;

        }
    }
}

